using System;

namespace Phoenix.Frames
{
    public class NavigationFrameController : ContentFrameController, INavigationFrameController
    {
        IFrameJournal journal;
        readonly object operationLock = new object();

        public NavigationFrameController(INavigationFrameControl navigationFrame) 
            : base(navigationFrame)
        {
        }

        protected override void OnNavigatingTo(NavigationRequest navigationRequest)
        {
            DeactivateCurrentRequest();
        }

        protected override void OnNavigatedTo(NavigationRequest navigationRequest)
        {
            if (navigationRequest.View != null)
                Journal.Add(navigationRequest);
        }

        public void NavigateBack()
        {
            if (!Host.AppDispatcher.CheckAccess())
            {
                Host.AppDispatcher.BeginInvoke(new Action(NavigateBack));
                return;
            }

            lock (operationLock)
            {
                if (!CanGoBack) return;
                var closingEventArgs = new RequestClosingEventArgs();
                CurrentRequestClosing(closingEventArgs);
                if (closingEventArgs.Cancel) return;

                Dispose();
                Journal.Pop();
                var request = Journal.Pop();

                if (request == null)
                    return;

                NavigateTo(request);

                //Force rebind, while not visible this view will not be listening to property changed events
                var view = request.View;
                if (view != null)
                {
                    var dataContext = view.DataContext;
                    view.DataContext = null;
                    view.DataContext = dataContext;
                }
            }
        }

        public void NavigateBackTo(string controller, string action)
        {
            NavigateBackTo(null, controller, action);
        }

        public void NavigateBackTo(string assembly, string controller, string action)
        {
            var closingEventArgs = new RequestClosingEventArgs();
            CurrentRequestClosing(closingEventArgs);
            if (closingEventArgs.Cancel) return;

            Journal.TrimTo(assembly, controller, action);
            NavigateBack();
        }

        public IFrameJournal Journal
        {
            get
            {
                return journal ?? (journal = new FrameJournal(Name));
            }
        }

        public bool CanGoBack
        {
            get
            {
                //If we have only a single thing in the backstack, we can't go back (we are on the only page in journal)
                return Journal.Count > 1;
            }
        }
    }
}